package com.example.datachangerecord.record.processor;


import com.example.datachangerecord.record.emun.RecordType;
import com.example.datachangerecord.record.emun.TableCol;
import com.example.datachangerecord.record.eneity.*;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @author xyj
 */
public abstract class CompareRecordProcessor extends AbstractRecordProcessor implements RecordCompare, Record, LogBodyDecorate {

    protected abstract UpdateUser getUpdateUser(ContextRecordData context);


    @Override
    protected void compareAndRecord(List<? extends ContextRecordData> context) {
        super.compareAndRecord(context);
        for (ContextRecordData contextRecordData : context) {
            compareAndRecord(contextRecordData);
        }
    }

    private void compareAndRecord(ContextRecordData context) {
        Table table = context.getTable();

        UpdateUser updateUser = getUpdateUser(context);

        //组合唯一列
        String[] keyLists = getKeyList(table);


        List<LinkedHashMap<String, Object>> perData = context.getPerData();
        List<LinkedHashMap<String, Object>> afterData = context.getAfterData();


        HashMap<String, CompareBody> compareMap = classify(perData, afterData, keyLists);

        //获得记录对象
        List<LogBody> compares = toCompare(compareMap, table, updateUser);

        processLogBody(compares);

    }

    private void processLogBody(List<LogBody> compares) {
        decorate(compares);
        record(compares);
    }


    private List<LogBody> toCompare(HashMap<String, CompareBody> compareMap, Table table, UpdateUser updateUser) {
        List<LogBody> result = new LinkedList<>();
        Set<String> strings = compareMap.keySet();
        strings.forEach(key -> {
                    List<LogBody> compare = toCompare(compareMap.get(key), table, updateUser);
                    result.addAll(compare);
                }
        );
        return result;
    }

    @Override
    public List<LogBody> toCompare(CompareBody compareBody, Table table, UpdateUser updateUser) {
        ArrayList<LogBody> result = new ArrayList<>();
        LinkedHashMap<String, Object> per = compareBody.getPer();
        LinkedHashMap<String, Object> after = compareBody.getAfter();

        if (CollectionUtils.isEmpty(per) && !CollectionUtils.isEmpty(after)) {
            //新增
            LogBody logBody = createLogBody(after, table, updateUser, RecordType.CREATE);
            result.add(logBody);
        }
        if (!CollectionUtils.isEmpty(per) && CollectionUtils.isEmpty(after)) {
            // 删除
            LogBody logBody = createLogBody(per, table, updateUser, RecordType.DELETE);
            // 删除了可能查不到数据了,填充不了主要描述
            addPerMainDesc(per, logBody, table);

            result.add(logBody);
        }

        if (!CollectionUtils.isEmpty(per) && !CollectionUtils.isEmpty(after)) {
            // 修改
            TableCol[] concernFields = table.getConcernFields();
            if (concernFields != null && concernFields.length > 0) {
                List<LogBody> logBodies = updateLog(per, after, table, updateUser);
                result.addAll(logBodies);
            }
        }
        return result;
    }

    protected abstract void addPerMainDesc(LinkedHashMap<String, Object> per, LogBody logBody, Table table);


    private List<LogBody> updateLog(LinkedHashMap<String, Object> per, LinkedHashMap<String, Object> after, Table table, UpdateUser updateUser) {
        LinkedList<LogBody> lists = new LinkedList<>();
        TableCol[] concernFields = table.getConcernFields();
        for (TableCol concernField : concernFields) {
            Object perObject = per.get(concernField.name());
            Object afterObject = after.get(concernField.name());
            if (!perObject.equals(afterObject)) {
                LogBody logBody = createLogBody(per, table, updateUser, RecordType.UPDATE);
                //有变化
                logBody.setFieldName(concernField.name());
                logBody.setFieldDesc(concernField.getDesc());
                logBody.setPerData(String.valueOf(perObject));
                logBody.setAfterData(String.valueOf(afterObject));
                lists.add(logBody);
            }
        }
        return lists;
    }

    private LogBody getLogBody(LinkedHashMap<String, Object> after, Table table, UpdateUser updateUser, RecordType recordType) {
        String userId = updateUser.getUserId();
        String userName = updateUser.getUserName();
        String ip = updateUser.getIp();
        String desc = recordType.getDesc() + table.getDesc();
        String colName = table.getSelectCols().get(0).getColName();
        //操作对象
        String operateTarget = String.valueOf(after.get(colName));
        String remark = table.getRemark();
        LogBody logBody = new LogBody();
        logBody.setUserId(userId);
        logBody.setUserName(userName);
        logBody.setDesc(desc);
        logBody.setOperateTarget(operateTarget);
        logBody.setRemark(remark);
        logBody.setTableName(table.getName());
        logBody.setRecordType(recordType.name());
        logBody.setIp(ip);
        return logBody;
    }

    private LogBody createLogBody(LinkedHashMap<String, Object> after, Table table, UpdateUser updateUser, RecordType recordType) {
        LogBody logBody = getLogBody(after, table, updateUser, recordType);
        processHelpCol(table, after, logBody);
        return logBody;
    }

    private void processHelpCol(Table table, LinkedHashMap<String, Object> data, LogBody logBody) {
        if (!CollectionUtils.isEmpty(table.getHelpCols())) {
            //说明是中间表
            ColumnData columnData = table.getHelpCols().get(0);
            String colName = columnData.getColName();
            Object o = data.get(colName);
            logBody.setHelpValue(String.valueOf(o));
        }
    }


    private HashMap<String, CompareBody> classify(List<LinkedHashMap<String, Object>> perData, List<LinkedHashMap<String, Object>> afterData, String[] keyLists) {
        HashMap<String, CompareBody> result = new HashMap<>();
        perData.forEach(e -> {
            String key = getKey(e, keyLists);
            if (result.containsKey(key)) {
                result.get(key).setPer(e);
            } else {
                result.put(key, CompareBody.builder().key(key).per(e).build());
            }
        });

        afterData.forEach(e -> {
            String key = getKey(e, keyLists);
            if (result.containsKey(key)) {
                result.get(key).setAfter(e);
            } else {
                result.put(key, CompareBody.builder().key(key).after(e).build());
            }
        });
        return result;
    }

    private String getKey(LinkedHashMap<String, Object> map, String[] keyLists) {
        StringBuilder result = new StringBuilder();
        for (String keyList : keyLists) {
            result.append(map.get(keyList));
        }
        return result.toString();
    }


    private String[] getKeyList(Table table) {
        List<ColumnData> selectCols = table.getSelectCols();
        List<ColumnData> helpCols = table.getHelpCols();
        String[] keyLists = new String[selectCols.size() + helpCols.size()];

        int index = 0;

        for (ColumnData selectCol : selectCols) {
            keyLists[index] = selectCol.getColName();
            index = index + 1;
        }

        for (ColumnData helpCol : helpCols) {
            keyLists[index] = helpCol.getColName();
            index = index + 1;
        }
        return keyLists;
    }


}
